home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / EBKSRC.ARJ / EB2.CPP < prev    next >
C/C++ Source or Header  |  1991-07-31  |  15KB  |  598 lines

  1. /*
  2.  
  3.     eb2.cpp
  4.     7-31-91
  5.     Electronic Book
  6.  
  7.  
  8.     Copyright 1991
  9.     John W. Small
  10.     All rights reserved
  11.  
  12.     Licensed users of FlexList may use and modify this
  13.     tool for use in their programs.
  14.  
  15.  
  16.     PSW / Power SoftWare
  17.     P.O. Box 10072
  18.     McLean, Virginia 22102 8072 USA
  19.  
  20.     Voice: (703) 759-3838
  21.     CIS: 73757,2233
  22.  
  23.  
  24.     Notes:  The Electronic Book was coded to demonstrate
  25.     the various uses of FlexList.
  26.  
  27.  
  28. */
  29.  
  30. #include <ctype.h>
  31. #include <dos.h>
  32.  
  33. #include <eb1.hpp>
  34. #include <eb2.hpp>
  35. #include <pckey.hpp>
  36. #include <pcput2.hpp>
  37. #include <pcframe.hpp>
  38.  
  39.  
  40.  
  41. HyperLaunch::HyperLaunch(int imageX, int imageY,
  42.     const char *launch)
  43. {
  44.     ix = imageX;
  45.     iy = imageY;
  46.     this->launch = launch;
  47.     ilen = 0;
  48.     if (!launch)
  49.         return;
  50.     for (/* no init */; ilen < MAX_HYPER_LINE &&
  51.         launch[ilen]; ilen++)
  52.         if (launch[ilen] == HYPER_LAUNCH_DELIMIT)
  53.             break;
  54. }
  55.  
  56. void HyperLaunch::hilite(int winleft, int wintop,
  57.     int winwidth, int winheight, int attr)
  58. {
  59.     int x, y, i, l;
  60.  
  61.     if (iy < wintop)
  62.         return;
  63.     if ((y = iy - wintop + 1) > winheight)
  64.         return;
  65.     if (ix < winleft)
  66.         if (ix + ilen <= winleft)
  67.             return;  // launch left of window
  68.         else  {
  69.             x = 1;
  70.             i = winleft - ix;
  71.             if ((l = ilen - i) > winwidth)
  72.                 l = winwidth;
  73.         }
  74.     else if ((x = ix - winleft + 1) > winwidth)
  75.         return;  // launch right of window
  76.     else  {
  77.         i = 0;
  78.         if (x + ilen >= winwidth)
  79.             l = winwidth - x + 1;
  80.         else
  81.             l = ilen;
  82.     }
  83.     gotoxy(x,y);
  84.     textattr(attr);
  85.     cprintf("%.*s",l,&launch[i]);
  86. }
  87.  
  88. int HyperLaunch::match(const char *prefix, int pfLen)
  89. {
  90.     if (pfLen <= ilen)
  91.         if (!strncmpi(prefix,launch,pfLen))
  92.             return ix+pfLen-1;
  93.     return 0;
  94. }
  95.  
  96.  
  97. Palette HyperContext::defaultP =  {
  98.  
  99.     0,  /*  monochrome         or         color  */
  100.  
  101.     svideo(BLACK,LIGHTGRAY),    svideo(WHITE,BLUE),
  102.     svideo(DARKGRAY,LIGHTGRAY),    svideo(LIGHTRED,BLUE),
  103.     svideo(WHITE,BLACK),        svideo(BLUE,LIGHTGRAY)
  104. };
  105.  
  106. int HyperContext::defaultTabSpacing = 8;
  107.  
  108. void HyperContext::findLinesAndLaunches()
  109. {
  110.     int x, y, l;
  111.     unsigned inLaunch, i;
  112.     char *nline;
  113.     HyperLauncH HL;
  114.  
  115.     if ((nline = context) == (char *)0)
  116.         return;
  117.     for (x = y = 1, inLaunch = i = 0; i < clen; i++)  {
  118.         if (nline)  {
  119.             lines.insQD(&nline);
  120.             nline = (char *)0;
  121.         }
  122.         switch(context[i])  {
  123.         case HYPER_LAUNCH_DELIMIT:
  124.             if (context[i+1] ==
  125.                 HYPER_LAUNCH_DELIMIT)  {
  126.                 i++;
  127.                 x++;
  128.                 continue;
  129.             }
  130.             if (inLaunch)
  131.                 inLaunch = !inLaunch;
  132.             else if ((HL = new(launches.insQD())
  133.                 HyperLaunch(x,y,
  134.                 &context[++i]))
  135.                 != HyperLauncH0)  {
  136.                 l = HL->len();
  137.                 i += l;
  138.                 x += l;
  139.             }
  140.             else
  141.                 inLaunch  = !inLaunch;
  142.             break;
  143.         case '\r':
  144.             if (context[i+1] == '\n')
  145.                 i++;
  146.         case '\n':
  147.             x = 1;
  148.             y++;
  149.             nline = &context[i+1];
  150.             break;
  151.         case TAB:
  152.             while (x++ % tabSpacing)
  153.                 /* null stmt */;
  154.             break;
  155.         default:
  156.             x++;
  157.             break;
  158.         }
  159.     }
  160. }
  161.  
  162. HyperContext::HyperContext(char *context, unsigned clen,
  163.     const char *inlinks, const char *outlinks,
  164.     unsigned startRow, unsigned startColumn,
  165.     unsigned cursorRow, unsigned cursorColumn,
  166.     unsigned topicNum)
  167.     : lines(sizeof(char *)),
  168.     launches(sizeof(HyperLaunch))
  169. {
  170.     this ->context = context;
  171.     this->inlinks = strdup(inlinks);
  172.     this->outlinks = strdup(outlinks);
  173.     this->clen = clen;
  174.     choice = 0;
  175.     setPalette();
  176.     this->startRow = startRow;
  177.     this->startColumn = startColumn;
  178.     this->cursorRow = cursorRow;
  179.     this->cursorColumn = cursorColumn;
  180.     this->topicNum = topicNum;
  181.     tabSpacing = defaultTabSpacing;
  182.     prefix[pfLen=0] = '\0';
  183.     lines.setMaxNodes(MAX_HYPER_TOPIC_LINES);
  184.     launches.setMaxNodes(MAX_HYPER_TOPIC_LAUNCHES);
  185.     findLinesAndLaunches();
  186. }
  187.  
  188. HC_ACTIONS HyperContext::view()
  189. {
  190.     struct text_info ti;
  191.     ScrLnBuf scrbuf;
  192.     char *nline;
  193.     int x, y, i;
  194.     unsigned pgHeight, winHeight;
  195.     unsigned oldStartColumn, oldStartRow;
  196.     unsigned char scrollAttr;
  197.     unsigned scrollTopLeft, scrollBottomRight;
  198.     unsigned oldChoice;
  199.     HyperLauncH HL;
  200.  
  201.     PCF.reset();
  202.     gettextinfo(&ti);
  203.     mappalette(P);
  204.     mapvideo(NORMAL,P);
  205.     winHeight = ti.winbottom - ti.wintop + 1;
  206.     pgHeight = winHeight - 1;
  207.     scrbuf.set(mapattr(NORMAL,P),mapattr(HILITE,P),
  208.         ti.winright-ti.winleft+1,startColumn,1,'\r',
  209.         HYPER_LAUNCH_DELIMIT,tabSpacing);
  210.     if (cursorRow >= startRow + winHeight)
  211.         startRow = cursorRow - winHeight + 1;
  212.     else if (cursorRow < startRow)
  213.         startRow = cursorRow;
  214.     oldStartColumn = oldStartRow = 0;
  215.     scrollAttr = mapattr(NORMAL,P);
  216.     scrollBottomRight = ((ti.winbottom-1) << 8)
  217.         | (ti.winright-1);
  218.     scrollTopLeft = ((ti.wintop-1) << 8)
  219.         | (ti.winleft-1);
  220.  
  221.     prefix[pfLen = 0] = '\0';
  222.     oldChoice = choice = 0;
  223.  
  224.  
  225. while (1)  {
  226.     if (pfLen)  {  // find typed in hyper link
  227.         choice = 0;
  228.         for (launches.mkcur(); (HL = (HyperLauncH)
  229.             launches.nextD()) != HyperLauncH0;
  230.             /* no reinit */)  {
  231.             if ((x = HL->match(prefix,pfLen)) != 0)  {
  232.                 cursorColumn = x + 1;
  233.                 choice = launches.CurNum();
  234.                 cursorRow = HL->IY();
  235.                 break;
  236.             }
  237.         }
  238.         if (!choice)
  239.             prefix[pfLen = 0] = '\0';
  240.     }
  241.     else if (oldChoice != choice)  // find tabbed to hyper link
  242.         if ((HL = (HyperLauncH) launches.mkcur(choice))
  243.             != HyperLauncH0)  {
  244.             cursorRow = HL->IY();
  245.             cursorColumn = HL->IX();
  246.         }
  247.     if (cursorRow < startRow)
  248.         startRow = cursorRow;
  249.     else if (cursorRow >= startRow + winHeight)
  250.         startRow = cursorRow - winHeight + 1;
  251.     if (cursorColumn < scrbuf.startColumn)
  252.         scrbuf.startColumn = cursorColumn;
  253.     else if (cursorColumn >= scrbuf.startColumn
  254.         + scrbuf.pgWidth)
  255.         scrbuf.startColumn = cursorColumn
  256.             - scrbuf.pgWidth + 1;
  257.     if (oldStartColumn != scrbuf.startColumn ||
  258.         oldStartRow != startRow)  {
  259.         if (oldStartColumn == scrbuf.startColumn &&
  260.             oldStartRow &&
  261.             ((((y = oldStartRow-startRow) > 0)?
  262.             y : -y) <= 1))  {
  263.             // scroll up/down and insert line.
  264.             _DX = scrollBottomRight;
  265.             _CX = scrollTopLeft;
  266.             _BH = scrollAttr;
  267.             _AX = (y > 0)? 0x0701 : 0x0601;
  268.             geninterrupt(0x10);
  269.             y = (( y > 0)? startRow : startRow
  270.                 + winHeight - 1);
  271.             if (lines.recallD(&nline,y))
  272.                 scrbuf.put(nline,ti.winleft,
  273.                 ti.wintop+y-startRow);
  274.         }
  275.         else  {
  276.             lines.mkcur(startRow-1);
  277.             for (y = 0; y < winHeight &&
  278.                 lines.nextD(&nline); y++)  {
  279.                 scrbuf.put(nline,
  280.                     ti.winleft,ti.wintop+y);
  281.             }
  282.             while (y < winHeight)
  283.                 scrbuf.put((char *)0,
  284.                     ti.winleft,ti.wintop+y++);
  285.         }
  286.         oldStartColumn = scrbuf.startColumn;
  287.         oldStartRow = startRow;
  288.     }
  289.     if (!pfLen)  {  // find cursor moved over hyper link
  290.         choice = 0;
  291.         for (launches.mkcur(); (HL = (HyperLauncH)
  292.             launches.nextD()) != HyperLauncH0;
  293.             /* no reinit */)
  294.             if (HL->onLaunchPad(cursorColumn,cursorRow))  {
  295.                 choice = launches.CurNum();
  296.                 break;
  297.             }
  298.     }
  299.     if (oldChoice != choice)  { // New hyper link to hilite
  300.         if ((HL = (HyperLauncH) launches.mkcur(oldChoice))
  301.             != HyperLauncH0)
  302.             HL->hilite(scrbuf.startColumn,startRow,
  303.                 scrbuf.pgWidth,winHeight,
  304.                 mapattr(HILITE,P));
  305.         if ((HL = (HyperLauncH) launches.mkcur(choice))
  306.             != HyperLauncH0)
  307.             HL->hilite(scrbuf.startColumn,startRow,
  308.                 scrbuf.pgWidth,winHeight,
  309.                     mapattr(SELECT,P));
  310.         oldChoice = choice;
  311.     }
  312.     startColumn = scrbuf.startColumn; // save for hyperstack
  313.     gotoxy(cursorColumn-startColumn+1,
  314.         cursorRow-startRow+1);
  315.     pfLen = 0;   // get ready to erase prefix if not added to
  316.     switch (PCK.getkey())  {
  317.     case -Home:
  318.         cursorColumn = scrbuf.startColumn = 1;
  319.         break;
  320.     case -EndKey:
  321.         // compute line length;
  322.         if (lines.recallD(&nline,cursorRow))  {
  323.             scrbuf.writebuf(nline);
  324.             cursorColumn = scrbuf.eolColumn;
  325.         }
  326.         else
  327.             cursorColumn = 1;
  328.         if (cursorColumn < scrbuf.startColumn)
  329.             scrbuf.startColumn = cursorColumn;
  330.         else if (cursorColumn >=
  331.             scrbuf.startColumn + scrbuf.pgWidth)
  332.             scrbuf.startColumn = cursorColumn
  333.                 - scrbuf.pgWidth + 1;
  334.         break;
  335.     case CtrlS:
  336.     case -LArr:
  337.         if (cursorColumn > 1)
  338.             if (--cursorColumn < scrbuf.startColumn)
  339.                 scrbuf.startColumn = cursorColumn;
  340.         break;
  341.     case CtrlD:
  342.     case -RArr:
  343.         if (cursorColumn < MAX_HYPER_LINE)
  344.             if (++cursorColumn >=
  345.                 scrbuf.startColumn + scrbuf.pgWidth)
  346.                 scrbuf.startColumn = cursorColumn
  347.                 - scrbuf.pgWidth + 1;
  348.         break;
  349.     case -UpArr:
  350.         if (cursorRow > 1)
  351.             if (--cursorRow < startRow)
  352.                 startRow = cursorRow;
  353.         break;
  354.     case -DnArr:
  355.         if (cursorRow < lines.Nodes())  {
  356.             if (++cursorRow >= startRow + winHeight)
  357.                 startRow = cursorRow - winHeight + 1;
  358.         }
  359.         else if (startRow < cursorRow)
  360.             startRow++;
  361.         break;
  362.     case CtrlA:
  363.     case -CtrlLArr:
  364.         if (lines.recallD(&nline,cursorRow))  {
  365.             scrbuf.writebuf(nline);
  366.             if (cursorColumn > scrbuf.eolColumn)
  367.                 i = scrbuf.eolColumn - 1;
  368.             else
  369.                 i = cursorColumn - 1;
  370.             while (i && !isalnum((char)scrbuf.buf[i-1]))
  371.                 i--;
  372.             if (!i)  {
  373.                 if (cursorRow == 1)
  374.                     break;
  375.                 if (lines.recallD(&nline,cursorRow-1)) {
  376.                     cursorRow--;
  377.                     scrbuf.writebuf(nline);
  378.                     cursorColumn = scrbuf.eolColumn;
  379.                 }
  380.                 break;
  381.             }
  382.             while (i && isalnum((char)scrbuf.buf[i-1]))
  383.                 i--;
  384.             cursorColumn = i + 1;
  385.         }
  386.         break;
  387.     case CtrlF:
  388.     case -CtrlRArr:
  389.         lines.mkcur(cursorRow-1);
  390.         for (i = cursorColumn - 1; lines.nextD(&nline);
  391.             i = 0)  {
  392.             scrbuf.writebuf(nline);
  393.             x = scrbuf.eolColumn - 1;
  394.             if (i >= x)
  395.                 continue;
  396.             while (i < x && isalnum((char)scrbuf.buf[i])) i++;
  397.             if (i >= x)
  398.                 break;
  399.             while (i < x && !isalnum((char)scrbuf.buf[i])) i++;
  400.             if (i < x)
  401.                 break;
  402.         }
  403.         if (lines.CurNum())  {
  404.             cursorRow = lines.CurNum();
  405.             cursorColumn = i + 1;
  406.         }
  407.         break;
  408.     case -CtrlHome:
  409.         cursorRow = startRow;
  410.         break;
  411.     case -CtrlEnd:
  412.         if (startRow + winHeight - 1 > lines.Nodes())
  413.             cursorRow = lines.Nodes();
  414.         else
  415.             cursorRow = startRow + winHeight - 1;
  416.         break;
  417.     case -PgDn:
  418.         cursorRow += pgHeight;
  419.         if (cursorRow >= lines.Nodes())  {
  420.             cursorRow = lines.Nodes();
  421.             if (startRow + pgHeight > cursorRow)
  422.                 break;
  423.         }
  424.         startRow += pgHeight;
  425.         if (startRow > cursorRow)
  426.             startRow = cursorRow;
  427.         break;
  428.     case -PgUp:
  429.         if (cursorRow > pgHeight)
  430.             cursorRow -= pgHeight;
  431.         else
  432.             cursorRow = 1;
  433.         if (startRow > pgHeight)
  434.             startRow -= pgHeight;
  435.         else
  436.             startRow = 1;
  437.         break;
  438.     case -CtrlPgUp:
  439.         startRow = cursorRow = 1;
  440.         break;
  441.     case -CtrlPgDn:
  442.         cursorRow = lines.Nodes();
  443.         if (cursorRow >= startRow + winHeight)
  444.                 if (cursorRow > winHeight/2)
  445.                     startRow = cursorRow
  446.                         - winHeight/2;
  447.                 else
  448.                     startRow = 1;
  449.         break;
  450.     case CtrlZ:  // pan down
  451.         if (startRow < lines.Nodes())
  452.             if (++startRow > cursorRow)
  453.                 cursorRow = startRow;
  454.         break;
  455.     case CtrlW:  // pan up
  456.         if (startRow > 1)
  457.             if (--startRow + winHeight <= cursorRow)
  458.                 cursorRow = startRow + winHeight - 1;
  459.         break;
  460.     case -F1:
  461.         mapvideo(NORMAL,P);
  462.         clrscr();
  463.     cputs("\n\n\r      F1                  Help"
  464.           "\n\n\r      F3                  Load new HyperText file"
  465.           "\n\n\r      F10, AltT           Table of Contents"
  466.           "\n\n\r      AltF10, AltI        Index"
  467.           "\n\n\r      CR                  Tranverse HyperLink"
  468.           "\n\n\r      AltF1, BACKSP       Backtrack HyperLink"
  469.           "\n\n\r      F6                  Toggle 25 - 43/50 lines"
  470.           "\n\n\r      ShiftF6             Toggle monochrome/color"
  471.           "\n\n\r      AltX                Exit"
  472.           "\n\n\n\n\r      Your choice ...");
  473.         while (!PCK.kbhit()) /* null stmt */;
  474.         oldStartColumn = oldStartRow = 0;
  475.         oldChoice = choice = 0;  // hilite if required
  476.         break;
  477.     case -F3: return LOAD;
  478.     case -F10:
  479.     case -AltT:
  480.         return TABLE_OF_CONTENTS;
  481.     case -AltF10:
  482.     case -AltI:
  483.         return INDEX;
  484.     case CR:
  485.         choice = 0;
  486.         for (launches.mkcur(); (HL = (HyperLauncH)
  487.             launches.nextD()) != HyperLauncH0;
  488.             /* no reinit */)
  489.             if (HL->onLaunchPad(cursorColumn,cursorRow))  {
  490.                 choice = launches.CurNum();
  491.                 return LAUNCH;
  492.             }
  493.         break;
  494.     case -AltF1:
  495.     case BACKSP:
  496.         return BACKUP;
  497.     case -ShiftF6:
  498.         forcedmonochrome = !forcedmonochrome;
  499.         mappalette(P);
  500.         mapvideo(NORMAL,P);
  501.         oldStartColumn = oldStartRow = 0;
  502.         scrbuf.set(mapattr(NORMAL,P),mapattr(HILITE,P),
  503.             ti.winright-ti.winleft+1,startColumn,1,'\r',
  504.             HYPER_LAUNCH_DELIMIT,tabSpacing);
  505.         oldChoice = choice = 0;  // hilite if required
  506.         break;
  507.     case -F6:
  508.         toggleRes();
  509.         PCF.reset();
  510.         gettextinfo(&ti);
  511.         mappalette(P);
  512.         mapvideo(NORMAL,P);
  513.         winHeight = ti.winbottom - ti.wintop + 1;
  514.         pgHeight = winHeight - 1;
  515.         scrbuf.set(mapattr(NORMAL,P),mapattr(HILITE,P),
  516.             ti.winright-ti.winleft+1,startColumn,1,'\r',
  517.             HYPER_LAUNCH_DELIMIT,tabSpacing);
  518.         if (cursorRow >= startRow + winHeight)
  519.             startRow = cursorRow - winHeight + 1;
  520.         else if (cursorRow < startRow)
  521.             startRow = cursorRow;
  522.         oldStartColumn = oldStartRow = 0;
  523.         scrollAttr = mapattr(NORMAL,P);
  524.         scrollBottomRight = ((ti.winbottom-1) << 8)
  525.             | (ti.winright-1);
  526.         scrollTopLeft = ((ti.wintop-1) << 8)
  527.             | (ti.winleft-1);
  528.         oldChoice = choice = 0;  // hilite if required
  529.         break;
  530.     case -AltX: return EXIT;
  531.     case TAB:
  532.         if (!choice)  {  // find closest launch to cursor
  533.             for (launches.mkcur(); (HL = (HyperLauncH)
  534.                 launches.nextD()) != HyperLauncH0;
  535.                 /* no reinit */)
  536.                 if ((HL->IY() > cursorRow) ||
  537.                     ((HL->IY() == cursorRow) &&
  538.                     ((HL->IX() + HL->len())
  539.                     > cursorColumn)))
  540.                     break;
  541.             if ((choice = launches.CurNum()) == 0)
  542.                 choice = 1;
  543.         }
  544.         else if (choice < launches.Nodes())
  545.             choice++;
  546.         else
  547.             choice = 1;
  548.         break;
  549.     case -ShiftTab:
  550.         if (!choice)  {  // find closest launch to cursor
  551.             for (launches.mkcur(); (HL = (HyperLauncH)
  552.                 launches.prevD()) != HyperLauncH0;
  553.                 /* no reinit */)
  554.                 if ((HL->IY() < cursorRow) ||
  555.                     ((HL->IY() == cursorRow) &&
  556.                     (HL->IX() < cursorColumn)))
  557.                     break;
  558.             if ((choice = launches.CurNum()) == 0)
  559.                 choice = launches.Nodes();
  560.         }
  561.         else if (choice > 1)
  562.             choice--;
  563.         else
  564.             choice = launches.Nodes();
  565.         break;
  566.     default:
  567.         if ((pfLen = strlen(prefix)) >= MAX_HC_PREFIX - 1)
  568.                 continue;
  569.         if (!isprint(PCK.ascii()))
  570.             continue;
  571.         prefix[pfLen++] = toupper(PCK.ascii());
  572.         break;
  573.     }
  574.     prefix[pfLen] = '\0';
  575. }
  576.     return EXIT;
  577. }
  578.  
  579. char * HyperContext::newTarget()
  580. {
  581.     char *t;
  582.  
  583.     if (!choice) return (char *)0;
  584.     t = parseLinks(outlinks);
  585.     for (unsigned i = 1; i < choice; i++)
  586.         t = parseLinks();
  587.     return t;
  588. }
  589.  
  590. HyperContext::~HyperContext()
  591. {
  592.     delete context;
  593.     lines.clear();
  594.     launches.clear();
  595.     delete inlinks;
  596.     delete outlinks;
  597. }
  598.